package cn.ug.activity.mq;

import cn.ug.activity.bean.BonusBean;
import cn.ug.activity.mapper.entity.*;
import cn.ug.activity.service.ActivityInvitationService;
import cn.ug.activity.service.BonusService;
import cn.ug.activity.service.CouponMemberService;
import cn.ug.activity.service.MemberInvestmentRewardsService;
import cn.ug.bean.base.SerializeObject;
import cn.ug.bean.type.ResultType;
import cn.ug.config.AplicationResourceProperties;
import cn.ug.core.SerializeObjectError;
import cn.ug.enums.BonusTypeEnum;
import cn.ug.enums.CouponTriggerEnum;
import cn.ug.enums.ProductTypeEnum;
import cn.ug.enums.WxTemplateEnum;
import cn.ug.feign.*;
import cn.ug.member.bean.response.MemberUserBean;
import cn.ug.msg.mq.Msg;
import cn.ug.msg.mq.WxMessageParamBean;
import cn.ug.msg.mq.WxNotifyData;
import cn.ug.pay.bean.response.BankCardFindBean;
import cn.ug.pay.bean.response.MemberAccountBean;
import cn.ug.pay.bean.type.BillGoldTradeType;
import cn.ug.pay.bean.type.TradeType;
import cn.ug.product.bean.response.ProductFindBean;
import cn.ug.util.BigDecimalUtil;
import cn.ug.util.DateUtils;
import cn.ug.util.UF;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static cn.ug.config.QueueName.*;
import static cn.ug.util.RedisConstantUtil.REWARDS_ERROR_KEY;

@Component
@RabbitListener(queues = QUEUE_ACTIVITY_REWARDS)
public class RewardsReceiver {
    private Log log = LogFactory.getLog(RewardsReceiver.class);
    private ObjectMapper mapper = new ObjectMapper();
    @Autowired
    private CouponMemberService couponMemberService;
    @Autowired
    private ProductService productService;
    @Autowired
    private MemberAccountService memberAccountService;
    @Autowired
    private MemberGoldService memberGoldService;
    @Autowired
    private MemberUserService memberUserService;
    @Autowired
    private BonusService bonusService;
    @Autowired
    private MemberInvestmentRewardsService memberInvestmentRewardsService;
    @Autowired
    protected AplicationResourceProperties properties;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private ActivityInvitationService activityInvitationService;
    @Autowired
    private BankCardService bankCardService;

    @RabbitHandler
    public void process(RewardsMQ o) throws JsonProcessingException {
        log.info("RewardsReceiver.process");
        if (o == null) {
            return;
        }
        log.info(mapper.writeValueAsString(o));
        String key = REWARDS_ERROR_KEY + o.getOrderId()+o.getMemberId();
        String value = redisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(value)) {
            int num = Integer.parseInt(value);
            if (num > 15) {
                return;
            }
        }

        String numValue = redisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(numValue)) {
            int num = Integer.parseInt(numValue);
            num++;
            redisTemplate.opsForValue().set(key, String.valueOf(num), 3600, TimeUnit.SECONDS);
        } else {
            redisTemplate.opsForValue().set(key, String.valueOf(1), 3600, TimeUnit.SECONDS);
        }
        int scene = o.getScene();
        if (scene == 1) {
            couponMemberService.giveCoupons(o.getMemberId(), CouponTriggerEnum.BINDED_CARD.getTrigger());
        } else if (scene == 2) {
            couponMemberService.giveCoupons(o.getMemberId(), CouponTriggerEnum.TRANSACTION.getTrigger());
        } else if (scene == 3) {
            couponMemberService.giveCoupons(o.getMemberId(), CouponTriggerEnum.PAY_EXPERIENCE.getTrigger());
        } else if (scene == 4) {
            couponMemberService.giveCoupons(o.getMemberId(), CouponTriggerEnum.LEASEBACK.getTrigger());
            SerializeObject<ProductFindBean> productBean = productService.queryProductById(o.getProductId());
            if (productBean != null && productBean.getCode() == ResultType.NORMAL && productBean.getData() != null) {
                ProductFindBean product = productBean.getData();
                if (product != null && product.getType() == ProductTypeEnum.ENTITY.getType() && o.getLeasebackDays() >= 30) {
                    handleInvitationRewards(o, product);
                }
            } else {
                throw new RuntimeException("产品服务异常.");
            }
        }
    }

    public static double computeIncomeAmount(double payAmount, double hadInvestmentAmount, List<ActivityInvitationStrategy> strategies ) {
        double totalAmount = payAmount + hadInvestmentAmount;
        double income = 0;
        double lastInvestmentAmount = hadInvestmentAmount;
        for (ActivityInvitationStrategy strategy : strategies) {
            double investmentAmount = strategy.getInvestmentAmount().doubleValue()*10000;
            if (strategy.getMark() == 1) {
                if (totalAmount > investmentAmount) {
                    if (investmentAmount > hadInvestmentAmount) {
                        if (hadInvestmentAmount < lastInvestmentAmount) {
                            income += (investmentAmount-lastInvestmentAmount)/100.0*strategy.getProportion().doubleValue();
                        } else {
                            income += (investmentAmount-hadInvestmentAmount)/100.0*strategy.getProportion().doubleValue();
                        }
                    } else {
                        //income += (totalAmount-investmentAmount)*financeDays/36500*strategy.getProportion().doubleValue();
                       /* int index = strategies.indexOf(strategy);
                        if (index < strategies.size()) {
                            income += (strategies.get(index+1).getInvestmentAmount().doubleValue()*10000-hadInvestmentAmount)/100.0*strategy.getProportion().doubleValue();
                        } else {
                            income += (totalAmount-hadInvestmentAmount)/100.0*strategy.getProportion().doubleValue();
                        }*/
                    }
                    lastInvestmentAmount = investmentAmount;
                } else {
                    if (totalAmount > lastInvestmentAmount) {
                        if (hadInvestmentAmount < lastInvestmentAmount) {
                            income += (totalAmount-lastInvestmentAmount)/100.0*strategy.getProportion().doubleValue();
                        } else {
                            income += (totalAmount-hadInvestmentAmount)/100.0*strategy.getProportion().doubleValue();
                        }
                    }
                    lastInvestmentAmount = investmentAmount;
                }
            } else if (strategy.getMark() == 2) {
                if (totalAmount > investmentAmount) {
                    if (hadInvestmentAmount > investmentAmount) {
                        income += payAmount/100.0*strategy.getProportion().doubleValue();
                    } else {
                        income += (totalAmount-investmentAmount)/100.0*strategy.getProportion().doubleValue();
                    }
                } else {
                    continue;
                }
                lastInvestmentAmount = investmentAmount;
            } else {
                break;
            }
        }
        return income;
    }

    public void handleInvitationRewards(RewardsMQ o, ProductFindBean product) {
        SerializeObject<MemberUserBean> bean = memberUserService.findById(o.getMemberId());
        if(null == bean || bean.getCode() != ResultType.NORMAL || bean.getData() == null) {
            log.error(new SerializeObjectError("22000008").getMsg());
            return;
        }
        MemberUserBean user = bean.getData();
        if (StringUtils.isBlank(user.getFriendId())) {
            return;
        }
        SerializeObject<BankCardFindBean> cardBean =  bankCardService.getBankCard(user.getId());
        if (null == cardBean || cardBean.getCode() != ResultType.NORMAL || cardBean.getData() == null) {
            throw new RuntimeException("请求投资者银行卡信息出错.");
        }
        BankCardFindBean card = cardBean.getData();
        int activityInvitationId = user.getActivityInvitationId();
        if (activityInvitationId == 0) {
            return;
        }
        SerializeObject<MemberUserBean> friendBean = memberUserService.findById(user.getFriendId());
        if (null == friendBean || friendBean.getCode() != ResultType.NORMAL || friendBean.getData() == null) {
            return;
        }
        MemberUserBean friend = friendBean.getData();
        if (o.getPayTotalAmount() == null || o.getPayTotalAmount().doubleValue() <= 0) {
            return;
        }
        LocalDateTime registerTime = UF.getDateTime(card.getAddTime());
        LocalDateTime plusRegisterTime = registerTime.plusDays( properties.getInvitationIndate());
        LocalDateTime currentTime =  UF.getDateTime();
        if (currentTime.isAfter(plusRegisterTime)) {
            return;
        }
        ActivityInvitation activityInvitation = activityInvitationService.get(activityInvitationId);
        if (activityInvitation == null || activityInvitation.getStatus() != 2) {
            return;
        }
        if (activityInvitation.getStrategyies() == null || activityInvitation.getStrategyies().size() == 0) {
            return;
        }
        double payAmount = o.getPayTotalAmount().doubleValue();
        double hadInvestmentAmount = memberInvestmentRewardsService.selectInvestmentAmount(user.getId(), activityInvitationId);
        List<ActivityInvitationStrategy> strategies = activityInvitation.getStrategyies();
        log.info("方案：" + JSONObject.toJSONString(strategies));
        log.info(o.getMemberId()+"：已投资金额：" + hadInvestmentAmount);
        double income = computeIncomeAmount(payAmount, hadInvestmentAmount, strategies);
        if (income <= 0) {
            return;
        }
        BigDecimal decimal = BigDecimalUtil.to2Point(new BigDecimal(income).multiply(new BigDecimal(0.7)));
        SerializeObject result = memberAccountService.inviteReturnCash(friend.getId(), decimal, TradeType.INVITATION_BACK.getValue());
        if(result != null && result.getCode() == ResultType.NORMAL) {
            Msg msg = new Msg();
            msg.setMemberId(friend.getId());
            msg.setType(cn.ug.msg.bean.status.CommonConstants.MsgType.INVITE_INVIST_RETURN_AWARD.getIndex());
            Map<String, String> paramMap = new HashMap<>();
            paramMap.put("amount", String.valueOf(decimal.doubleValue()));
            paramMap.put("productName", product.getName());
            msg.setParamMap(paramMap);
            amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);
            MemberInvestmentRewards entity = new MemberInvestmentRewards();
            entity.setAmount(decimal.doubleValue());
            entity.setFriend(user);
            entity.setActivityInvitationId(activityInvitationId);
            entity.setInvestmentAmount(o.getPayTotalAmount());
            entity.setType(3);
            entity.setId(UF.getRandomUUID());
            entity.setBillId(result.getMsg());
            entity.setOrderId(o.getOrderId());
            entity.setMemberId(friend.getId());
            memberInvestmentRewardsService.save(entity);

            SerializeObject<MemberAccountBean> memberAccount = memberAccountService.findByMemberId(friend.getId());
            /**
             * 微信服务号消息推送  收支变动
             */
            WxMessageParamBean wxMessageParamBean = new WxMessageParamBean();
            wxMessageParamBean.setMemberId(friend.getId());
            wxMessageParamBean.setType(WxTemplateEnum.FUND_CHANGE.getType());
            WxTemplateEnum wxTemplateEnum = WxTemplateEnum.getWxTemplateByCode(WxTemplateEnum.FUND_CHANGE.getType());
            WxNotifyData wxNotifyData = new WxNotifyData();

            Map<String,WxNotifyData.TemplateDataAttr> wxParamMap = new HashMap();
            WxNotifyData.TemplateDataAttr first = new WxNotifyData.TemplateDataAttr();
            first.setDataValue(wxTemplateEnum.getFirstData());
            wxParamMap.put("first",first);

            WxNotifyData.TemplateDataAttr keyword1 = new WxNotifyData.TemplateDataAttr();
            keyword1.setDataValue(TradeType.INVITATION_BACK.getRemark());
            wxParamMap.put("keyword1",keyword1);

            WxNotifyData.TemplateDataAttr keyword2 = new WxNotifyData.TemplateDataAttr();
            keyword2.setDataValue(String.valueOf(decimal.doubleValue()));
            wxParamMap.put("keyword2",keyword2);

            WxNotifyData.TemplateDataAttr keyword3 = new WxNotifyData.TemplateDataAttr();
            keyword3.setDataValue(DateUtils.dateToStr(new Date(),DateUtils.patter));
            wxParamMap.put("keyword3",keyword3);


            WxNotifyData.TemplateDataAttr keyword4 = new WxNotifyData.TemplateDataAttr();
            keyword4.setDataValue(BigDecimalUtil.to2Point(memberAccount.getData().getUsableAmount()).toString());
            wxParamMap.put("keyword4",keyword4);

            WxNotifyData.TemplateDataAttr remark = new WxNotifyData.TemplateDataAttr();
            remark.setDataValue(wxTemplateEnum.getRemark());
            wxParamMap.put("remark",remark);

            wxNotifyData.setData(wxParamMap);
            wxMessageParamBean.setTemplateData(wxNotifyData);
            amqpTemplate.convertAndSend(QUEUE_MSG_WX_SEND, wxMessageParamBean);
        } else {
            throw new RuntimeException("赠送邀请返现出错.");
        }
        try {
            Thread.sleep(45000);
        } catch (Exception e) {

        }
        decimal = BigDecimalUtil.to2Point(new BigDecimal(income).multiply(new BigDecimal(0.3)));
        result = memberAccountService.inviteReturnCash(user.getId(), decimal, TradeType.INVITATION_BACK.getValue());
        if(result != null && result.getCode() == ResultType.NORMAL) {
            Msg msg = new Msg();
            msg.setMemberId(user.getId());
            msg.setType(cn.ug.msg.bean.status.CommonConstants.MsgType.INVITE_INVIST_RETURN_AWARD.getIndex());
            Map<String, String> paramMap = new HashMap<>();
            paramMap.put("amount", String.valueOf(decimal.doubleValue()));
            paramMap.put("productName", product.getName());
            msg.setParamMap(paramMap);
            amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);
            MemberInvestmentRewards entity = new MemberInvestmentRewards();
            entity.setAmount(decimal.doubleValue());
            entity.setActivityInvitationId(activityInvitationId);
            entity.setInvestmentAmount(o.getPayTotalAmount());
            entity.setType(3);
            entity.setFriend(user);
            entity.setId(UF.getRandomUUID());
            entity.setBillId(result.getMsg());
            entity.setOrderId(o.getOrderId());
            entity.setMemberId(user.getId());
            memberInvestmentRewardsService.save(entity);

            SerializeObject<MemberAccountBean> memberAccount = memberAccountService.findByMemberId(user.getId());
            /**
             * 微信服务号消息推送  收支变动
             */
            WxMessageParamBean wxMessageParamBean = new WxMessageParamBean();
            wxMessageParamBean.setMemberId(user.getId());
            wxMessageParamBean.setType(WxTemplateEnum.FUND_CHANGE.getType());
            WxTemplateEnum wxTemplateEnum = WxTemplateEnum.getWxTemplateByCode(WxTemplateEnum.FUND_CHANGE.getType());
            WxNotifyData wxNotifyData = new WxNotifyData();

            Map<String,WxNotifyData.TemplateDataAttr> wxParamMap = new HashMap();
            WxNotifyData.TemplateDataAttr first = new WxNotifyData.TemplateDataAttr();
            first.setDataValue(wxTemplateEnum.getFirstData());
            wxParamMap.put("first",first);

            WxNotifyData.TemplateDataAttr keyword1 = new WxNotifyData.TemplateDataAttr();
            keyword1.setDataValue(TradeType.INVITATION_BACK.getRemark());
            wxParamMap.put("keyword1",keyword1);

            WxNotifyData.TemplateDataAttr keyword2 = new WxNotifyData.TemplateDataAttr();
            keyword2.setDataValue(String.valueOf(decimal.doubleValue()));
            wxParamMap.put("keyword2",keyword2);

            WxNotifyData.TemplateDataAttr keyword3 = new WxNotifyData.TemplateDataAttr();
            keyword3.setDataValue(DateUtils.dateToStr(new Date(),DateUtils.patter));
            wxParamMap.put("keyword3",keyword3);


            WxNotifyData.TemplateDataAttr keyword4 = new WxNotifyData.TemplateDataAttr();
            keyword4.setDataValue(BigDecimalUtil.to2Point(memberAccount.getData().getUsableAmount()).toString());
            wxParamMap.put("keyword4",keyword4);

            WxNotifyData.TemplateDataAttr remark = new WxNotifyData.TemplateDataAttr();
            remark.setDataValue(wxTemplateEnum.getRemark());
            wxParamMap.put("remark",remark);

            wxNotifyData.setData(wxParamMap);
            wxMessageParamBean.setTemplateData(wxNotifyData);
            amqpTemplate.convertAndSend(QUEUE_MSG_WX_SEND, wxMessageParamBean);
        }
    }

    private void handleBonus(RewardsMQ o) {
        SerializeObject<MemberUserBean> bean = memberUserService.findById(o.getMemberId());
        if(null == bean || bean.getCode() != ResultType.NORMAL || bean.getData() == null) {
            log.error(new SerializeObjectError("22000008").getMsg());
            return;
        }
        ProductBonusMapping productBonusMapping = bonusService.findByProductId(o.getProductId());
        if (productBonusMapping == null || StringUtils.isBlank(productBonusMapping.getBonusId())) {
            log.error(new SerializeObjectError("22000009").getMsg());
            return;
        }
        BonusBean bonus = bonusService.get(productBonusMapping.getBonusId());
        if (bonus == null) {
            log.error(new SerializeObjectError("22000009").getMsg());
            return;
        }
        List<BonusStrategy> strategies = bonusService.listStrategies(productBonusMapping.getBonusId());
        if (strategies == null || strategies.size() == 0) {
            log.error(new SerializeObjectError("22000009").getMsg());
            return;
        }
        if (o.getPayTotalAmount() == null) {
            return;
        }
        if (giveProductBouns(bonus, strategies, o.getPayTotalAmount().doubleValue(), bean.getData().getId())) {
            log.info(new SerializeObject(ResultType.NORMAL, "00000001").getMsg());
        } else {
            log.error(new SerializeObject(ResultType.ERROR, "00000005").getMsg());
        }
    }

    public boolean giveProductBouns(BonusBean bonus, List<BonusStrategy> strategies, double principal, String userId) {
        int index = 0;
        for (BonusStrategy strategy : strategies) {
            if (principal >= strategy.getQuota()) {
                index++;
            } else {
                break;
            }
        }
        if (index > 0) {
            BonusStrategy strategy = strategies.get(index - 1);
            if (strategy != null) {
                if (bonus.getType() == BonusTypeEnum.INTEREST.getType() || bonus.getType() == BonusTypeEnum.KICKBACK.getType()) {
                    String couponId = strategy.getCouponId();
                    double amount = couponMemberService.giveCoupon(userId, couponId);
                    if (amount > 0) {
                        return true;
                    } else  {
                        return false;
                    }
                } else if (bonus.getType() == BonusTypeEnum.CASH.getType()) {
                    double amount = strategy.getAmount();
                    BigDecimal decimal = new BigDecimal(amount);
                    SerializeObject bean = memberAccountService.inviteReturnCash(userId, decimal, TradeType.REBATE.getValue());
                    if(null == bean || bean.getCode() != ResultType.NORMAL) {
                        return false;
                    }
                } else if (bonus.getType() == BonusTypeEnum.GOLD.getType()) {
                    double amount = strategy.getAmount();
                    BigDecimal decimal = new BigDecimal(amount);
                    SerializeObject bean = memberGoldService.investRebate(userId, decimal, BillGoldTradeType.REBATE.getValue());
                    if(null == bean || bean.getCode() != ResultType.NORMAL) {
                        return false;
                    }
                } else ;
            }
        }
        return true;
    }
}
